package org.jawa.service.impl;

import java.util.List;

import javax.jws.WebService;
import javax.persistence.EntityExistsException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jawa.dao.UserDao;
import org.jawa.model.User;
import org.jawa.service.UserExistsException;
import org.jawa.service.UserManager;
import org.jawa.service.UserService;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.userdetails.UsernameNotFoundException;

@WebService(serviceName = "UserService", endpointInterface = "org.jawa.service.UserService")
public class UserManagerImpl implements UserManager, UserService {

	private Log log=LogFactory.getLog(UserManagerImpl.class);
	private UserDao userDao;
	private PasswordEncoder passwordEncoder;

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	public User getUser(String userId) {
		return userDao.getUser(new Long(userId));
	}

	/**
	 * Set the PasswordEncoder used to encrypt passwords.
	 * 
	 * @param passwordEncoder
	 *            the PasswordEncoder implementation
	 */
	@Required
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public User saveUser(User user) throws UserExistsException {
		if (user.getId() == null) {
			// if new user, lowercase userId
			user.setUsername(user.getUsername().toLowerCase());
		}

		// Get and prepare password management-related artifacts
		boolean passwordChanged = false;
		if (passwordEncoder != null) {
			// Check whether we have to encrypt (or re-encrypt) the password
			if (user.getId() == null) {
				// New user, always encrypt
				passwordChanged = true;
			} else {
				// Existing user, check password in DB
				String currentPassword = userDao.getUserPassword(user
						.getUsername());
				if (currentPassword == null) {
					passwordChanged = true;
				} else {
					if (!currentPassword.equals(user.getPassword())) {
						passwordChanged = true;
					}
				}
			}

			// If password was changed (or new user), encrypt it
			if (passwordChanged) {
				user.setPassword(passwordEncoder.encodePassword(user
						.getPassword(), null));
			}
		} else {
			log.warn("PasswordEncoder not set, skipping password encryption...");
		}

		try {
			return userDao.saveUser(user);
		} catch (DataIntegrityViolationException e) {
			e.printStackTrace();
			log.warn(e.getMessage());
			throw new UserExistsException("User '" + user.getUsername()
					+ "' already exists!");
		} catch (EntityExistsException e) { // needed for JPA
			e.printStackTrace();
			log.warn(e.getMessage());
			throw new UserExistsException("User '" + user.getUsername()
					+ "' already exists!");
		}
	}

	public void removeUser(String userId) {
		userDao.removeUser(new Long(userId));
	}

	@Override
	public User getUserByUsername(String username)
			throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		return (User)userDao.loadUserByUsername(username);
	}

	@Override
	public List<User> getUsers(User user) {
		// TODO Auto-generated method stub
		return userDao.getUsers();
	}
}
